﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Globalization;
using System.Linq;
using DslModeling=global::Microsoft.VisualStudio.Modeling;
using DslValidation=global::Microsoft.VisualStudio.Modeling.Validation;

namespace Salamanca.Sdml
{

    partial class DomainEnum:
        IAttribute,
        IDataTableHolder,
        IComparable<DomainEnum>
    {

        /// <summary>Ensures that enumeration values are not duplicated.</summary>
        [DslValidation.ValidationMethod(DslValidation.ValidationCategories.Menu | DslValidation.ValidationCategories.Open | DslValidation.ValidationCategories.Save)]
        private void ValidateEnumValues(DslValidation.ValidationContext context)
        {
            if (Values.Count==0)
                context.LogWarning(
                    string.Format(
                        CultureInfo.CurrentCulture,
                        Resources.SR.EnumerationShouldHaveValues,
                        this.Name ?? string.Empty
                    ),
                    "SDML09",
                    new DslModeling.ModelElement[] { this }
                );

            Dictionary<string, IList<DslModeling.ModelElement>> values=new Dictionary<string, IList<DslModeling.ModelElement>>(StringComparer.InvariantCulture);
            _ValidateEnumValues(values, this);

            foreach (IList<DslModeling.ModelElement> duplicates in values.Values.Where(list => list.Count>1))
                context.LogError(
                    string.Format(
                        CultureInfo.CurrentCulture,
                        Resources.SR.UnderlyingValueCannotBeDuplicatedInEnumeration,
                        ((EnumValue)duplicates[0]).UnderlyingValue
                    ),
                    "SDML10",
                    duplicates.ToArray()
                );

            Dictionary<string, IList<DslModeling.ModelElement>> names=new Dictionary<string, IList<DslModeling.ModelElement>>(StringComparer.InvariantCultureIgnoreCase);
            _ValidateEnumValueNames(names, this);

            foreach (IList<DslModeling.ModelElement> duplicates in names.Values.Where(list => list.Count>1))
                context.LogError(
                    string.Format(
                        CultureInfo.CurrentCulture,
                        Resources.SR.ValueNameCannotBeDuplicatedInEnumeration,
                        ((EnumValue)duplicates[0]).Name
                    ),
                    "SDML11",
                    duplicates.ToArray()
                );
        }

        /// <summary>Helper method that fills a <paramref name="values">dictionary</paramref>
        /// with the values of an <paramref name="enumeration" />.</summary>
        /// <param name="values">A <see cref="IDictionary" /> which associates values to enumeration items.</param>
        /// <param name="enumeration">The enumeration for which the values are parsed.</param>
        private void _ValidateEnumValues(IDictionary<string, IList<DslModeling.ModelElement>> values, DomainEnum enumeration)
        {
            foreach (EnumValue ev in enumeration.Values)
            {
                if (string.IsNullOrEmpty(ev.UnderlyingValue))
                    continue;

                if (!values.ContainsKey(ev.UnderlyingValue))
                    values.Add(ev.UnderlyingValue, new List<DslModeling.ModelElement>(new DslModeling.ModelElement[] { ev }));
                else
                    values[ev.UnderlyingValue].Add(ev);
            }
        }

        /// <summary>Helper method that fills a <paramref name="values">dictionary</paramref>
        /// with the names of the values of an <paramref name="enumeration" />.</summary>
        /// <param name="names">A <see cref="IDictionary" /> which associates value names to enumeration items.</param>
        /// <param name="enumeration">The enumeration for which the value names are parsed.</param>
        private void _ValidateEnumValueNames(IDictionary<string, IList<DslModeling.ModelElement>> names, DomainEnum enumeration)
        {
            foreach (EnumValue ev in enumeration.Values)
            {
                if (string.IsNullOrEmpty(ev.Name))
                    continue;

                if (!names.ContainsKey(ev.Name))
                    names.Add(ev.Name, new List<DslModeling.ModelElement>(new DslModeling.ModelElement[] { ev }));
                else
                    names[ev.Name].Add(ev);
            }
        }

        internal int CompareTo(DomainEnum other)
        {
            if (other==null)
                return 1;

            return Name.CompareTo(other.Name);
        }

        int IComparable<DomainEnum>.CompareTo(DomainEnum other)
        {
            return CompareTo(other);
        }

        public DataTable DataTable
        {
            get
            {
                DomainModel.LoadDataSet();
                return (DataTable)_TableReference.Target;
            }
            internal set
            {
                _TableReference=new WeakReference(value);
            }
        }

        int IAttribute.MaxLength
        {
            get
            {
                if (Array.IndexOf(EnumTypesProviderConverter.IntegralTypes, UnderlyingType)>=0)
                    return -1;

                return Values.Max<EnumValue>(v => v.UnderlyingValue.Length);
            }
        }

        string IAttribute.Type
        {
            get
            {
                return UnderlyingType;
            }
        }

        private WeakReference _TableReference;
    }
}
